package src

import (
	"math"

	"gitee.com/haifengat/goctp/v2"
	zd "gitee.com/haifengat/zorm-dm/v2"
)

type BaseColumn struct {
	zd.Entity
	InsertTime DateTimeType
	UpdateTime DateTimeType
}

type DateTimeType string

// yyyy-MM-dd HH:mm:ss
func (DateTimeType) GetDataType() string {
	return "varchar(19)"
}

type TradingDayType string

func (TradingDayType) GetDataType() string {
	return "varchar(8)"
}

type ExchangeIDType string

func (ExchangeIDType) GetDataType() string {
	return "varchar(8)"
}

type InvestorIDType string

func (InvestorIDType) GetDataType() string {
	return "varchar(32)"
}

type InstrumentField struct {
	InstrumentID      string `zorm:"primaryKey;size:32"`
	InstrumentName    string `zorm:"size:128"`
	ProductID         string `zorm:"size:32"`
	ExchangeID        ExchangeIDType
	PriceTick         float64
	VolumeMultiple    int
	UnderlyingInstrID string `zorm:"size:32"`
	ProductClass      goctp.TThostFtdcProductClassType
	OptionsType       goctp.TThostFtdcOptionsTypeType
	// 上市日
	OpenDate string `zorm:"size:8"`
	// 到期日
	ExpireDate string `zorm:"size:8"`
	BaseColumn
}

// Bar 分钟K线
type Bar struct {
	DateTime     string         `zorm:"primarykey"` // redis 标识
	InstrumentID string         `zorm:"primarykey;size:64"`
	TradingDay   TradingDayType `zorm:"index"`
	Open         float64
	High         float64
	Low          float64
	Close        float64
	Volume       int
	OpenInterest float64
	PreVol       int
	Ticks        int // 此分钟的tick数量 >3 才会被记录和分发
	zd.Entity
	// BaseColumn
}

// 入库或返回查询数据时使用
func (b *Bar) Fix() *Bar {
	b.Open = math.Trunc(b.Open*1000000) / 1000000
	b.Close = math.Trunc(b.Close*1000000) / 1000000
	b.High = math.Trunc(b.High*1000000) / 1000000
	b.Low = math.Trunc(b.Low*1000000) / 1000000
	b.OpenInterest = math.Trunc(b.OpenInterest*1000000) / 1000000
	return b
}

type Tick struct {
	// 交易日
	TradingDay TradingDayType
	// 合约代码
	InstrumentID string `zorm:"size:64"`
	// 交易所代码
	ExchangeID ExchangeIDType
	// 最新价
	LastPrice float64
	// 今开盘
	OpenPrice float64
	// 最高价
	HighestPrice float64
	// 最低价
	LowestPrice float64
	// 数量
	Volume int
	// 成交金额
	Turnover float64
	// 持仓量
	OpenInterest float64
	// 本次结算价
	SettlementPrice float64
	// 涨停板价
	UpperLimitPrice float64
	// 跌停板价
	LowerLimitPrice float64
	// 最后修改时间
	UpdateTime string `zorm:"size:8"`
	// 最后修改毫秒
	UpdateMillisec int
	// 申买价一
	BidPrice1 float64
	// 申买量一
	BidVolume1 int
	// 申卖价一
	AskPrice1 float64
	// 申卖量一
	AskVolume1 int
	// 当日均价
	AveragePrice float64
}

func (b *Tick) Fix() *Tick {
	if b.ExchangeID == "" {
		b.ExchangeID = ExchangeIDType(trd.Instruments[b.InstrumentID].ExchangeID.String())
	}
	if b.LastPrice == math.MaxFloat64 {
		b.LastPrice = -1
	} else {
		b.LastPrice = math.Trunc(b.LastPrice*1000000) / 1000000
	}
	if b.AskPrice1 == math.MaxFloat64 {
		b.AskPrice1 = -1
	} else {
		b.AskPrice1 = math.Trunc(b.AskPrice1*1000000) / 1000000
	}
	if b.BidPrice1 == math.MaxFloat64 {
		b.BidPrice1 = -1
	} else {
		b.BidPrice1 = math.Trunc(b.BidPrice1*1000000) / 1000000
	}
	if b.AveragePrice == math.MaxFloat64 {
		b.AveragePrice = -1
	} else {
		b.AveragePrice = math.Trunc(b.AveragePrice*1000000) / 1000000
	}
	if b.SettlementPrice == math.MaxFloat64 {
		b.SettlementPrice = -1
	} else {
		b.SettlementPrice = math.Trunc(b.SettlementPrice*1000000) / 1000000
	}
	if b.HighestPrice == math.MaxFloat64 {
		b.HighestPrice = -1
	} else {
		b.HighestPrice = math.Trunc(b.HighestPrice*1000000) / 1000000
	}
	if b.LowestPrice == math.MaxFloat64 {
		b.LowestPrice = -1
	} else {
		b.LowestPrice = math.Trunc(b.LowestPrice*1000000) / 1000000
	}
	if b.UpperLimitPrice == math.MaxFloat64 {
		b.UpperLimitPrice = -1
	} else {
		b.UpperLimitPrice = math.Trunc(b.UpperLimitPrice*1000000) / 1000000
	}
	if b.LowerLimitPrice == math.MaxFloat64 {
		b.LowerLimitPrice = -1
	} else {
		b.LowerLimitPrice = math.Trunc(b.LowerLimitPrice*1000000) / 1000000
	}
	b.OpenInterest = math.Trunc(b.OpenInterest*1000000) / 1000000
	b.OpenPrice = math.Trunc(b.OpenPrice*1000000) / 1000000
	return b
}

type AccountField struct {
	// 投资者帐号
	AccountID string
	// 上次结算准备金
	PreBalance float64
	// 入金金额
	Deposit float64
	// 出金金额
	Withdraw float64
	// 冻结的保证金
	FrozenMargin float64
	// 冻结的手续费
	FrozenCommission float64
	// 当前保证金总额
	CurrMargin float64
	// 资金差额
	CashIn float64
	// 手续费
	Commission float64
	// 平仓盈亏
	CloseProfit float64
	// 持仓盈亏
	PositionProfit float64
	// 期货结算准备金
	Balance float64
	// 可用资金
	Available float64
	// 可取资金
	WithdrawQuota float64
	// 基本准备金
	Reserve float64
	// 交易所保证金
	ExchangeMargin float64
	// 币种代码
	CurrencyID string
	BaseColumn
}

func (a *AccountField) FromCTP(v goctp.CThostFtdcTradingAccountField) *AccountField {
	a.AccountID = v.AccountID.String()
	a.PreBalance = float64(v.PreBalance)
	a.Deposit = float64(v.Deposit)
	a.Withdraw = float64(v.Withdraw)
	a.FrozenMargin = float64(v.FrozenMargin)
	a.FrozenCommission = float64(v.FrozenCommission)
	a.CurrMargin = float64(v.CurrMargin)
	a.CashIn = float64(v.CashIn)
	a.Commission = float64(v.Commission)
	a.CloseProfit = float64(v.CloseProfit)
	a.PositionProfit = float64(v.PositionProfit)
	a.Balance = float64(v.Balance)
	a.Available = float64(v.Available)
	a.WithdrawQuota = float64(v.WithdrawQuota)
	a.Reserve = float64(v.Reserve)
	a.ExchangeMargin = float64(v.ExchangeMargin)
	a.CurrencyID = v.CurrencyID.String()
	return a
}

type PositionField struct {
	// 投资者代码
	InvestorID string `zorm:"size:32"`
	// 持仓多空方向
	PosiDirection goctp.TThostFtdcPosiDirectionType
	// 投机套保标志
	HedgeFlag goctp.TThostFtdcHedgeFlagType
	// 上日持仓
	YdPosition int
	// 今日持仓
	Position int
	// 多头冻结
	LongFrozen int
	// 空头冻结
	ShortFrozen int
	// 开仓冻结金额
	LongFrozenAmount float64
	// 开仓冻结金额
	ShortFrozenAmount float64
	// 开仓量
	OpenVolume int
	// 平仓量
	CloseVolume int
	// 开仓金额
	OpenAmount float64
	// 平仓金额
	CloseAmount float64
	// 持仓成本
	PositionCost float64
	// 占用的保证金
	UseMargin float64
	// 冻结的保证金
	FrozenMargin float64
	// 冻结的资金
	FrozenCash float64
	// 冻结的手续费
	FrozenCommission float64
	// 资金差额
	CashIn float64
	// 手续费
	Commission float64
	// 平仓盈亏
	CloseProfit float64
	// 持仓盈亏
	PositionProfit float64
	// 交易日
	TradingDay TradingDayType
	// 开仓成本
	OpenCost float64
	// 交易所保证金
	ExchangeMargin float64
	// 逐日盯市平仓盈亏
	CloseProfitByDate float64
	// 逐笔对冲平仓盈亏
	CloseProfitByTrade float64
	// 今日持仓
	TodayPosition int
	// 执行冻结
	StrikeFrozen int
	// 执行冻结金额
	StrikeFrozenAmount float64
	// 放弃执行冻结
	AbandonFrozen int
	// 交易所代码
	ExchangeID ExchangeIDType
	// 执行冻结的昨仓
	YdStrikeFrozen int
	// 投资单元代码
	InvestUnitID string `zorm:"size:32"`
	// 持仓成本差值
	PositionCostOffset float64
	// 合约代码
	InstrumentID string `zorm:"size:64"`
	BaseColumn
}

func (p *PositionField) FromCTP(f goctp.CThostFtdcInvestorPositionField) *PositionField {
	p.AbandonFrozen = int(f.AbandonFrozen)
	p.CashIn = float64(f.CashIn)
	p.CloseAmount = float64(f.CloseAmount)
	p.CloseProfit = float64(f.CloseProfit)
	p.CloseProfitByDate = float64(f.CloseProfitByDate)
	p.CloseProfitByTrade = float64(f.CloseProfitByTrade)
	p.CloseVolume = int(f.CloseVolume)
	p.ExchangeID = ExchangeIDType(f.ExchangeID.String())
	p.ExchangeMargin = float64(f.ExchangeMargin)
	p.FrozenCash = float64(f.FrozenCash)
	p.FrozenCommission = float64(f.FrozenCommission)
	p.FrozenMargin = float64(f.FrozenMargin)
	p.HedgeFlag = f.HedgeFlag
	p.InstrumentID = f.InstrumentID.String()
	p.InvestUnitID = f.InvestUnitID.String()
	p.InvestorID = f.InvestorID.String()
	p.LongFrozen = int(f.LongFrozen)
	p.LongFrozenAmount = float64(f.LongFrozenAmount)
	p.OpenAmount = float64(f.OpenAmount)
	p.OpenCost = float64(f.OpenCost)
	p.OpenVolume = int(f.OpenVolume)
	p.PosiDirection = f.PosiDirection
	p.Position = int(f.Position)
	p.PositionCost = float64(f.PositionCost)
	p.PositionCostOffset = float64(f.PositionCostOffset)
	p.PositionProfit = float64(f.PositionProfit)
	p.ShortFrozen = int(f.ShortFrozen)
	p.ShortFrozenAmount = float64(f.ShortFrozenAmount)
	p.StrikeFrozen = int(f.StrikeFrozen)
	p.StrikeFrozenAmount = float64(f.StrikeFrozenAmount)
	p.TodayPosition = int(f.TodayPosition)
	p.TradingDay = TradingDayType(f.TradingDay.String())
	p.UseMargin = float64(f.UseMargin)
	p.YdPosition = int(f.YdPosition)
	p.YdStrikeFrozen = int(f.YdStrikeFrozen)
	return p
}

type OrderField struct {
	// 投资者代码
	InvestorID string `zorm:"size:32"`
	// 报单引用
	OrderRef string `zorm:"size:16"`
	// 用户代码
	UserID string `zorm:"size:32"`
	// 报单价格条件
	OrderPriceType goctp.TThostFtdcOrderPriceTypeType
	// 买卖方向
	Direction goctp.TThostFtdcDirectionType
	// 组合开平标志
	CombOffsetFlag goctp.TThostFtdcOffsetFlagType
	// 组合投机套保标志
	CombHedgeFlag goctp.TThostFtdcHedgeFlagType
	// 价格
	LimitPrice float64
	// 数量
	VolumeTotalOriginal int
	// 有效期类型
	TimeCondition goctp.TThostFtdcTimeConditionType
	// 成交量类型
	VolumeCondition goctp.TThostFtdcVolumeConditionType
	// 本地报单编号
	OrderLocalID string `zorm:"size:32"`
	// 交易所代码
	ExchangeID ExchangeIDType
	// 客户代码
	ClientID string `zorm:"size:16"`
	// 报单提交状态
	OrderSubmitStatus goctp.TThostFtdcOrderSubmitStatusType
	// 交易日
	TradingDay TradingDayType
	// 报单编号
	OrderSysID string `zorm:"size:32"`
	// 报单状态
	OrderStatus goctp.TThostFtdcOrderStatusType
	// 报单类型
	OrderType goctp.TThostFtdcOrderTypeType
	// 今成交数量
	VolumeTraded int
	// 剩余数量
	VolumeTotal int
	// 报单日期
	InsertDate TradingDayType
	// 委托时间
	OrderTime string `zorm:"size:8"`
	// 最后修改时间
	LastTime string `zorm:"size:8"`
	// 撤销时间
	CancelTime string `zorm:"size:8"`
	// 前置编号
	FrontID int
	// 会话编号
	SessionID int
	// 用户端产品信息
	UserProductInfo string `zorm:"size:32"`
	// 状态信息
	StatusMsg string `zorm:"size:128"`
	// 用户强评标志
	UserForceClose goctp.TThostFtdcBoolType
	// 相关报单(平仓对应的开仓)
	RelativeOrderSysID string `zorm:"size:32"`
	// 郑商所成交数量
	ZCETotalTradedVolume int
	// 投资单元代码
	InvestUnitID string `zorm:"size:32"`
	// 资金账号
	AccountID string `zorm:"size:32"`
	// 币种代码
	CurrencyID string `zorm:"size:8"`
	// 合约代码
	InstrumentID string `zorm:"size:64"`
	BaseColumn
}

func (o *OrderField) FromCTP(f goctp.CThostFtdcOrderField) *OrderField {
	o.InvestorID = f.InvestorID.String()
	o.OrderRef = f.OrderRef.String()
	o.UserID = f.UserID.String()
	o.OrderPriceType = f.OrderPriceType
	o.Direction = f.Direction
	o.CombOffsetFlag = goctp.TThostFtdcOffsetFlagType(f.CombOffsetFlag[0])
	o.CombHedgeFlag = goctp.TThostFtdcHedgeFlagType(f.CombHedgeFlag[0])
	o.LimitPrice = float64(f.LimitPrice)
	o.VolumeTotalOriginal = int(f.VolumeTotalOriginal)
	o.TimeCondition = f.TimeCondition
	o.VolumeCondition = f.VolumeCondition
	o.OrderLocalID = f.OrderLocalID.String()
	o.ExchangeID = ExchangeIDType(f.ExchangeID.String())
	o.ClientID = f.ClientID.String()
	o.OrderSubmitStatus = f.OrderSubmitStatus
	o.TradingDay = TradingDayType(f.TradingDay.String())
	o.OrderSysID = f.OrderSysID.String()
	o.OrderStatus = f.OrderStatus
	o.OrderType = f.OrderType
	o.VolumeTraded = int(f.VolumeTraded)
	o.VolumeTotal = int(f.VolumeTotal)
	o.InsertDate = TradingDayType(f.InsertDate.String())
	o.OrderTime = f.InsertTime.String()
	o.CancelTime = f.CancelTime.String()
	o.FrontID = int(f.FrontID)
	o.SessionID = int(f.SessionID)
	o.UserProductInfo = f.UserProductInfo.String()
	o.StatusMsg = f.StatusMsg.String()
	o.UserForceClose = f.UserForceClose
	o.RelativeOrderSysID = f.RelativeOrderSysID.String()
	o.ZCETotalTradedVolume = int(f.ZCETotalTradedVolume)
	o.InvestUnitID = f.InvestUnitID.String()
	o.AccountID = f.AccountID.String()
	o.CurrencyID = f.CurrencyID.String()
	o.InstrumentID = f.InstrumentID.String()
	return o
}

type TradeField struct {
	// 投资者代码
	InvestorID string `zorm:"size:32"`
	// 报单引用
	OrderRef string `zorm:"size:16"`
	// 用户代码
	UserID string `zorm:"size:32"`
	// 交易所代码
	ExchangeID ExchangeIDType
	// 成交编号
	TradeID string `zorm:"size:32"`
	// 买卖方向
	Direction goctp.TThostFtdcDirectionType
	// 报单编号
	OrderSysID string `zorm:"size:32"`
	// 开平标志
	OffsetFlag goctp.TThostFtdcOffsetFlagType
	// 投机套保标志
	HedgeFlag goctp.TThostFtdcHedgeFlagType
	// 价格
	Price float64
	// 数量
	Volume int
	// 成交时期
	TradeDate TradingDayType
	// 成交时间
	TradeTime string `zorm:"size:8"`
	// 成交类型
	TradeType goctp.TThostFtdcTradeTypeType
	// 交易所交易员代码
	TraderID string `zorm:"size:32"`
	// 交易日
	TradingDay TradingDayType
	// 投资单元代码
	InvestUnitID string `zorm:"size:32"`
	// 合约代码
	InstrumentID string `zorm:"size:64"`
	BaseColumn
}

func (t *TradeField) FromCTP(f goctp.CThostFtdcTradeField) *TradeField {
	// 投资者代码
	t.InvestorID = f.InvestorID.String()
	// 报单引用
	t.OrderRef = f.OrderRef.String()
	// 用户代码
	t.UserID = f.UserID.String()
	// 交易所代码
	t.ExchangeID = ExchangeIDType(f.ExchangeID.String())
	// 成交编号
	t.TradeID = f.TradeID.String()
	// 买卖方向
	t.Direction = f.Direction
	// 报单编号
	t.OrderSysID = f.OrderSysID.String()
	// 开平标志
	t.OffsetFlag = f.OffsetFlag
	// 投机套保标志
	t.HedgeFlag = f.HedgeFlag
	// 价格
	t.Price = float64(f.Price)
	// 数量
	t.Volume = int(f.Volume)
	// 成交时期
	t.TradeDate = TradingDayType(f.TradeDate.String())
	// 成交时间
	t.TradeTime = f.TradeTime.String()
	// 成交类型
	t.TradeType = f.TradeType
	// 交易所交易员代码
	t.TraderID = f.TradeID.String()
	// 交易日
	t.TradingDay = TradingDayType(f.TradeDate.String())
	// 投资单元代码
	t.InvestUnitID = f.InvestUnitID.String()
	// 合约代码
	t.InstrumentID = f.InstrumentID.String()
	return t
}

type OrderInsert struct {
	InstrumentID InvestorIDType
	Director     goctp.TThostFtdcDirectionType
	Offset       goctp.TThostFtdcOffsetFlagType
	Price        float64
	Volume       int
}
